package elastic

import (
	"context"
	"sync"
	"time"

	"gitee.com/yysama/Kindling_civilization/pkg/xutil"
	"github.com/olivere/elastic"
)

type Search struct {
	client  *elastic.Client
	index   string
	typ     string
	pk      string
	mapping string
}

var (
	pools = sync.Map{}
)

func NewClient(index, typ, pk, mapping string, DSN ...string) (*Search, error) {
	key, e := xutil.Md5(DSN)
	if e != nil {
		return nil, e
	}

	client, ok := pools.Load(key)
	if ok {
		return client.(*Search), nil
	} else {
		client, e := elastic.NewClient(
			elastic.SetURL(DSN...),
			elastic.SetSniff(false),
			elastic.SetHealthcheckInterval(10*time.Second),
			elastic.SetGzip(true),
		)
		if e != nil {
			return nil, e
		}
		Client := &Search{
			client:  client,
			index:   index,
			typ:     typ,
			pk:      pk,
			mapping: mapping,
		}
		pools.Store(key, Client)

		return Client, e
	}
}

//校验 index 是否存在
func (es *Search) IndexExists() (bool, error) {
	exists, e := es.client.IndexExists(es.index).Do(context.Background())
	if e != nil {
		return false, e
	}

	return exists, nil
}

//创建 index
func (es *Search) CreateIndex() (bool, error) {
	ret, e := es.client.CreateIndex(es.index).BodyString(es.mapping).Do(context.Background())
	if e != nil {
		return false, e
	}
	return ret.Acknowledged, nil
}

//重建 index
func (es *Search) ReCreateIndex(index string) error {
	_, e := es.client.Reindex().DestinationIndex(index).SourceIndex(es.index).Do(context.TODO())
	if e != nil {
		return e
	}

	return nil
}

//删除 index
func (es *Search) DelIndex(index ...string) (bool, error) {
	index = append(index, es.index)
	ret, e := es.client.DeleteIndex(index...).Do(context.Background())
	if e != nil {
		return false, e
	}
	return ret.Acknowledged, nil
}

//批量 插入 document
//datas []any
func (es *Search) Insert(datas []any) (*elastic.BulkResponse, error) {
	bulkRequest := es.client.Bulk()
	for _, data := range datas {
		doc := elastic.NewBulkIndexRequest().Index(es.index).Type(es.typ).Doc(data)
		bulkRequest = bulkRequest.Add(doc)
	}
	ret, e := bulkRequest.Do(context.Background())
	if e != nil {
		return nil, e
	}
	return ret, nil
}

//批量更新
//datas [Id]any
func (es *Search) Update(datas map[string]any) (*elastic.BulkResponse, error) {
	bulkRequest := es.client.Bulk()
	for Id, data := range datas {
		doc := elastic.NewBulkUpdateRequest().Index(es.index).Type(es.typ).Id(Id).Doc(data)
		bulkRequest = bulkRequest.Add(doc)
	}
	ret, e := bulkRequest.Do(context.Background())
	if e != nil {
		return nil, e
	}
	return ret, nil
}

//批量 删除 document
//indices [Id]
func (es *Search) Delete(datas []string) (*elastic.BulkResponse, error) {
	bulkRequest := es.client.Bulk()
	for _, Id := range datas {
		doc := elastic.NewBulkDeleteRequest().Index(es.index).Type(es.typ).Id(Id)
		bulkRequest = bulkRequest.Add(doc)
	}
	ret, e := bulkRequest.Do(context.Background())
	if e != nil {
		return nil, e
	}
	return ret, nil
}
